<?php

namespace 中文汇编器;

class rv32i
{
	private $机器指令名 = ['逻辑左移', '逻辑左移直接数', '逻辑右移', '逻辑右移直接数', '算数右移', '算数右移直接数', '加', '加直接数', 
		                   '减', '取直接数高位', 'PC加直接数高位', '异或', '异或直接数', '或', '或直接数', '与', '与直接数', '小于则置位',
		                   '小于直接数则置位', '无符小于则置位', '无符小于直接数则置位', '相等则转至', '不等则转至', '小于则转至', 
		                   '大于等于则转至', '无符小于则转至', '无符大于等于则转至', '直接数跳转至', '寄存器跳转至', '访存约束',
		                   '指令序约束', '环境调用', '环境断点', '字节加载', '取两字节', '取无符字节', '取无符两字节', '取四字节', '存字节',
		                   '存两字节', '存四字节', '存CSR', '置位CSR', '复位CSR', '存CSR直接数', '置位CSR直接数', '复位CSR直接数',
                           '用户模式返回', '机器模式返回', '管理模式返回', '中断等待'];

	private $寄存器名 = ['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'x7', 'x8', 'x9', 'x10',
                         'x11', 'x12', 'x13', 'x14', 'x15', 'x16', 'x17', 'x18', 'x19', 'x20',
                         'x21', 'x22', 'x23', 'x24', 'x25', 'x26', 'x27', 'x28', 'x29', 'x30', 'x31',
	                     'zero', 'ra', 'sp', 'gp', 'tp', 't0', 't1', 't2', 's0', 's1', 
	                     'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 
	                     's2', 's3', 's4', 's5', 's6', 's7', 's8', 's9', 's10', 's11', 
	                     't3', 't4', 't5', 't6', 'mvendorid', 'marchid', 'mimpid', 'mhartid', 'mstatus', 'misa', 'medeleg',
                         'mideleg', 'mie', 'mtvec', 'mcounteren', 'mstatush', 'mscratch', 'mepc', 'mcause', 'mtval', 'mip',
                         'minst', 'mtval2', 'pmpcfg0', 'pmpcfg1', 'pmpcfg2', 'pmpcfg3', 'pmpaddr0', 'pmpaddr1', 'pmpaddr2', 'pmpaddr3', 'pmpaddr4',
                         'pmpaddr5', 'pmpaddr6', 'pmpaddr7', 'pmpaddr8', 'pmpaddr9', 'pmpaddr10', 'pmpaddr11', 'pmpaddr12', 'pmpaddr13', 'pmpaddr14',
                         'pmpaddr15', 'mcycle', 'minstret', 'mcycleh', 'minstreth', 'cycle', 'time', 'instret', 'cycleh', 'timeh', 'instreth'];
	private $局部标签 = [];
	private $全局标签 = [];
	private $待翻译指令 = [];

	public function __construct($lLabel, $gLabel)
	{
		$this->局部标签 = $lLabel;
		$this->全局标签 = $gLabel;
		//echo "RV32I指令处理\n";

	}

	public function 判断($opName)
	{
	    //var_dump($opName);
		$jqzl = in_array($opName, $this->机器指令名);
		//var_dump($jqzl);
		if ($jqzl == true) 
			return true;
		else 
			return false;
	}

	public function 标签处理($ins)
	{
		$this->待翻译指令 = $ins;
		$opItem = mb_split('，', $ins["内容"]);
		//var_dump($opItem);
		switch ($opItem[0])
		{
			case '逻辑左移直接数':
            case '逻辑右移直接数':
            case '算术右移直接数':
            case '异或直接数':
            case '或直接数':
            case '与直接数':
            case '加直接数':
            case '寄存器跳转至':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
				$opItem[2] = $this->标签替换($opItem[2]);
				$regs = [$opItem[1], $opItem[4]];
				$this->合法寄存器名($regs); 
				break;
			case '逻辑左移':
            case '逻辑右移':
            case '算术右移':
            case '加':
            case '减':
            case '异或':
            case '或':
            case '与':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $regs = [$opItem[1], $opItem[2], $opItem[4]];
			    $this->合法寄存器名($regs);
                break;
            case '取直接数高位':
            case 'PC加直接数高位':
            case '直接数跳转至':
                if (count($opItem) != 4)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $opItem[1] = $this->标签替换($opItem[1]);
                $regs = [$opItem[3]];
                $this->合法寄存器名($regs);
				break;
            case '小于则置位':
            case '无符小于则置位':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $regs = [$opItem[1], $opItem[3], $opItem[4]];
                $this->合法寄存器名($regs);
                break;
            case '小于直接数则置位':
            case '无符小于直接数则置位':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $opItem[4] = $this->标签替换($opItem[4]);
                $regs = [$opItem[1], $opItem[3]];
                $this->合法寄存器名($regs);
                break;
            case '相等则转至':
            case '不等则转至':
            case '小于则转至':
            case '大于等于则转至':
            case '无符小于则转至':
            case '无符大于等于则转至':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $opItem[1] = $this->标签替换($opItem[1]);
                $regs = [$opItem[3], $opItem[4]];
                $this->合法寄存器名($regs);
                break;
            case '取字节':
            case '取两字节':
            case '取四字节':
            case '取无符字节':
            case '取无符两字节':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $opItem[2] = $this->标签替换($opItem[2]);
                $regs = [$opItem[1], $opItem[4]];
                $this->合法寄存器名($regs);
                break;
            case '存字节':
            case '存两字节':
            case '存四字节':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $opItem[4] = $this->标签替换($opItem[4]);
                $regs = [$opItem[1], $opItem[3]];
                $this->合法寄存器名($regs);
                break;
            case '存CSR':
                if (count($opItem) != 7)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $regs = [$opItem[1], $opItem[3], $opItem[5]];
                $this->合法寄存器名($regs);
                break;
            case '置位CSR':
            case '复位CSR':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $regs = [$opItem[1], $opItem[2], $opItem[4]];
                $this->合法寄存器名($regs);
                break;
            case '存CSR直接数':
                if (count($opItem) != 7)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $opItem[5] = $this->标签替换($opItem[5]);
                $regs = [$opItem[1], $opItem[3]];
                $this->合法寄存器名($regs);
                break;
            case '置位CSR直接数':
            case '复位CSR直接数':
                if (count($opItem) != 5)
                    exit('错误：' . $ins["文件名"] . '的第【' . $ins["行数"] . '】行，【' . $opItem[0] . '】指令不全');
                $opItem[2] = $this->标签替换($opItem[2]);
                $regs = [$opItem[1], $opItem[4]];
                $this->合法寄存器名($regs);
                break;
			default:
				//echo "标签处理过程\n";
		}

		$str = '';
		for ($i = 0; $i < count($opItem); $i++)
            $str = $str . $opItem[$i] . '，';

		$str = mb_substr($str, 0, mb_strlen($str)-1);
		//var_dump($str);
		return($str);
	}

	private function 标签替换($label)
	{
		$n = count($this->全局标签);
		for ($j = 0; $j < $n; $j++)
		{
			if ($this->全局标签[$j]["标签名"] == $label)
				return($label);
		}

		$n = count($this->局部标签);
		for ($j = 0; $j < $n; $j++)
		{
			if ($this->局部标签[$j]["标签名"] == ('_' . $this->待翻译指令["文件序号"]. '_' . $label))
				return('_' . $this->待翻译指令["文件序号"]. '_' . $label);
		}

        if (is_numeric($label) == true)
        {
            $num = intval($label, 0);
            return($num);
        }

        $chr2 = mb_substr($label, 0, 2);
        if ($chr2 == '0x' or $chr2 == '0b')
        {
            $chrOther2 = mb_substr($label, 2);
            if (is_numeric($chrOther2) == false)
                exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] . '】行，【' . $label . '】标签未定义');
            $num = intval($label, 0);
            return($num);
        }

        $chr1 = mb_substr($label, 0, 1);
        if ($chr1 == '0')
        {
            $chrOther1 = mb_substr($label, 1);
            if (is_numeric($chrOther1) == false)
                exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] .  '】行，【' . $label . '】标签未定义');
            $num = intval($label, 0);
            return($num);
        }

        exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] .  '】行，【' . $label . '】标签未定义');
	}

	private function 合法寄存器名($regs)
	{
	    //print_r($regs);
		for ($i = 0; $i < count($regs); $i++)
        {
            if (in_array($regs[$i], $this->寄存器名))
                continue;
            else
                exit('错误：' . $this->待翻译指令["文件名"] . '的第【' . $this->待翻译指令["行数"] . '】行，【' . $regs[$i] . '】是错误的寄存器名称');
        }
	}

	public function 合成二进制($insStr)
	{
	    $binCode = 0b0;
		$opItem = mb_split('，', $insStr);
		switch ($opItem[0])
		{
			//移动
			case '逻辑左移':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b001, $rd, 0b0110011);
				break;

			case '逻辑左移直接数':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$n = $n & 0b00011111;
				$n = (0b0000000 << 5) + $n;
				$binCode = $this->I类型($n, $rs1, 0b001, $rd, 0b0010011);
				break;

			case '逻辑右移':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b101, $rd, 0b0110011);
				break;

			case '逻辑右移直接数':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$n = $n & 0b00011111;
				$n = (0b0000000 << 5) + $n;
				$binCode = $this->I类型($n, $rs1, 0b101, $rd, 0b0010011);
				break;

			case '算术右移':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0100000, $rs2, $rs1, 0b101, $rd, 0b0110011);
				break;

			case '算术右移直接数':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$n = $n & 0b00011111;
				$n = (0b0100000 << 5) + $n;
				$binCode = $this->I类型($n, $rs1, 0b101, $rd, 0b0010011);
				break;

			//算术
			case '加':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b000, $rd, 0b0110011);
				break;

			case '加直接数':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$binCode = $this->I类型($n, $rs1, 0b000, $rd, 0b0010011);
				//var_dump($binCode);
				break;

			case '减':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0100000, $rs2, $rs1, 0b000, $rd, 0b0110011);
				break;

			case '取直接数高位':
				$rd = $this->寄存器($opItem[3]);
				$n = $this->直接数处理($opItem[1], 'U');
				$binCode = $this->U类型($n, $rd, 0b0110111);
				break;

			case 'PC加直接数高位':
				$rd = $this->寄存器($opItem[3]);
				$n = $this->直接数处理($opItem[1], 'U');
				$binCode = $this->U类型($n, $rd, 0b0010111);
				break;
			
			//逻辑
			case '异或':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b100, $rd, 0b0110011);
				break;
				
			case '异或直接数':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$binCode = $this->I类型($n, $rs1, 0b100, $rd, 0b0010011);
				break;

			case '或':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b110, $rd, 0b0110011);
				break;

			case '或直接数':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$binCode = $this->I类型($n, $rs1, 0b110, $rd, 0b0010011);
				break;

			case '与':
				$rs1 = $this->寄存器($opItem[1]);
				$rs2 = $this->寄存器($opItem[2]);
				$rd = $this->寄存器($opItem[4]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b111, $rd, 0b0110011);
				break;

			case '与直接数':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$binCode = $this->I类型($n, $rs1, 0b111, $rd, 0b0010011);
				break;
			
			//比较
			case '小于则置位':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$rd = $this->寄存器($opItem[1]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b010, $rd, 0b0110011);
				break;

			case '小于直接数则置位':
				$rs1 = $this->寄存器($opItem[3]);
				$rd = $this->寄存器($opItem[1]);
				$n = $this->直接数处理($opItem[4], 'I');
				$binCode = $this->I类型($n, $rs1, 0b010, $rd, 0b0010011);
				break;

			case '无符小于则置位':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$rd = $this->寄存器($opItem[1]);
				$binCode = $this->R类型(0b0000000, $rs2, $rs1, 0b011, $rd, 0b0110011);
				break;

			case '无符小于直接数则置位':
				$rs1 = $this->寄存器($opItem[3]);
				$rd = $this->寄存器($opItem[1]);
				$n = $this->直接数处理($opItem[4], 'I', 1);
				$binCode = $this->I类型($n, $rs1, 0b011, $rd, 0b0010011);
				break;

			//岔
			case '相等则转至':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[1], 'B');
				$binCode = $this->B类型($n[3], $n[1], $rs2, $rs1, 0b000, $n[0], $n[2], 0b1100011);
				break;

			case '不等则转至':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[1], 'B');
				$binCode = $this->B类型($n[3], $n[1], $rs2, $rs1, 0b001, $n[0], $n[2], 0b1100011);
				break;

			case '小于则转至':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[1], 'B');
				$binCode = $this->B类型($n[3], $n[1], $rs2, $rs1, 0b100, $n[0], $n[2], 0b1100011);
				break;

			case '大于等于则转至':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[1], 'B');
				$binCode = $this->B类型($n[3], $n[1], $rs2, $rs1, 0b101, $n[0], $n[2], 0b1100011);
				break;

			case '无符小于则转至':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[1], 'B', 1);
				$binCode = $this->B类型($n[3], $n[1], $rs2, $rs1, 0b110, $n[0], $n[2], 0b1100011);
				break;

			case '无符大于等于则转至':
				$rs1 = $this->寄存器($opItem[3]);
				$rs2 = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[1], 'B', 1);
				$binCode = $this->B类型($n[3], $n[1], $rs2, $rs1, 0b111, $n[0], $n[2], 0b1100011);
				break;

			//跳转
			case '直接数跳转至':
				$rd = $this->寄存器($opItem[3]);
				$n = $this->直接数处理($opItem[1], 'J');
				$binCode = $this->J类型($n[3], $n[0], $n[1], $n[2], $rd, 0b1101111);
				break;

			case '寄存器跳转至':
				$rs1 = $this->寄存器($opItem[1]);
				$rd = $this->寄存器($opItem[4]);
				$n = $this->直接数处理($opItem[2], 'I');
				$binCode = $this->I类型($n, $rs1, 0b000, $rd, 0b1100111);
				break;

			//存数据
            case '存字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rs2 = $this->寄存器($opItem[3]);
                $n = $this->直接数处理($opItem[4], 'S');
                $binCode = $this->S类型($n[1], $rs2, $rs1, 0b000, $n[0], 0b0100011);
                break;

            case '存两字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rs2 = $this->寄存器($opItem[3]);
                $n = $this->直接数处理($opItem[4], 'S');
                $binCode = $this->S类型($n[1], $rs2, $rs1, 0b001, $n[0], 0b0100011);
                break;

            case '存四字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rs2 = $this->寄存器($opItem[3]);
                $n = $this->直接数处理($opItem[4], 'S');
                $binCode = $this->S类型($n[1], $rs2, $rs1, 0b010, $n[0], 0b0100011);
                //var_dump($binCode);
                break;

            //取数据
            case '取字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[4]);
                $n = $this->直接数处理($opItem[2], 'I');
                $binCode = $this->I类型($n, $rs1, 0b000, $rd, 0b0000011);
                break;

            case '取两字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[4]);
                $n = $this->直接数处理($opItem[2], 'I');
                $binCode = $this->I类型($n, $rs1, 0b001, $rd, 0b0000011);
                break;

            case '取四字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[4]);
                $n = $this->直接数处理($opItem[2], 'I');
                $binCode = $this->I类型($n, $rs1, 0b010, $rd, 0b0000011);
                break;

            case '取无符字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[4]);
                $n = $this->直接数处理($opItem[2], 'I', 1);
                $binCode = $this->I类型($n, $rs1, 0b100, $rd, 0b0000011);
                break;

            case '取无符两字节':
                $rs1 = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[4]);
                $n = $this->直接数处理($opItem[2], 'I', 1);
                $binCode = $this->I类型($n, $rs1, 0b101, $rd, 0b0000011);
                break;

            case '指令顺序约束':
                $binCode = $this->I类型(0b000000000000, 0b00000, 0b001, 0b00000, 0b0001111);
                break;

            case '访存顺序约束':  #fence pred, succ
                $succ = (int)$opItem[1];
                $pred = (int)$opItem[2];
                $n = 0b0;
                $n = $n + $succ;
                $n = $n + ($pred << 4);
                $binCode = $this->I类型($n, 0b00000, 0b000, 0b00000, 0b0001111);
                break;

            case '环境调用':
                $binCode = $this->I类型(0b000000000000, 0b00000, 0b000, 0b00000, 0b1110011);
                break;

            case '环境断点':
                $binCode = $this->I类型(0b000000000001, 0b00000, 0b000, 0b00000, 0b1110011);
                break;

            case '存CSR':
                $csr = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[3]);
                $rs1 = $this->寄存器($opItem[5]);
                $binCode = $this->I类型($csr, $rs1, 0b001, $rd, 0b1110011);
                break;

            case '置位CSR':
                $csr = $this->寄存器($opItem[1]);
                $rs1 = $this->寄存器($opItem[2]);
                $rd = $this->寄存器($opItem[4]);
                $binCode = $this->I类型($csr, $rs1, 0b010, $rd, 0b1110011);
                break;

            case '复位CSR':
                $csr = $this->寄存器($opItem[1]);
                $rs1 = $this->寄存器($opItem[2]);
                $rd = $this->寄存器($opItem[4]);
                $binCode = $this->I类型($csr, $rs1, 0b011, $rd, 0b1110011);
                break;

            case '存CSR直接数':
                $csr = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[3]);
                $n = $this->直接数处理($opItem[5], 'CSR');
                $binCode = $this->I类型($csr, $n, 0b101, $rd, 0b1110011);
                break;

            case '置位CSR直接数':
                $csr = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[4]);
                $n = $this->直接数处理($opItem[2], 'CSR');
                $binCode = $this->I类型($csr, $n, 0b110, $rd, 0b1110011);
                break;

            case '复位CSR直接数':
                $csr = $this->寄存器($opItem[1]);
                $rd = $this->寄存器($opItem[4]);
                $n = $this->直接数处理($opItem[2], 'CSR');
                $binCode = $this->I类型($csr, $n, 0b111, $rd, 0b1110011);
                break;

            case '中断等待':
                $binCode = $this->R类型(0b0001000, 0b00101, 0b00000, 0b000, 0b00000, 0b1110011);
                break;

            case '机器模式返回':
                $binCode = $this->R类型(0b0011000, 0b00010, 0b00000, 0b000, 0b00000, 0b1110011);
                break;

            case '用户模式返回':
                $binCode = $this->R类型(0b0000000, 0b00010, 0b00000, 0b000, 0b00000, 0b1110011);
                break;

            case '管理模式返回':
                $binCode = $this->R类型(0b0001000, 0b00010, 0b00000, 0b000, 0b00000, 0b1110011);
                break;

        }
		return($binCode);
	}
		
	private function R类型($funct7, $rs2, $rs1, $funct3, $rd, $opCode)
	{
		//RISC-V是低地址尾端模式，因此opCode在最低位
		//寄存器都是5位，opcode都是7位
		$binCode = 0b0;
		$binCode = $binCode + $opCode;
		$binCode = $binCode + ($rd << 7);
		$binCode = $binCode + ($funct3 << 12);
		$binCode = $binCode + ($rs1 << 15);
		$binCode = $binCode + ($rs2 << 20);
		$binCode = $binCode + ($funct7 << 25);
		$binCode = pack("V", $binCode);
		return($binCode);
	}
	
	private function I类型($imm_0_11, $rs1, $funct3, $rd, $opCode)
	{
		$binCode = 0b0;
		$binCode = $binCode + $opCode;
		$binCode = $binCode + ($rd << 7);
		$binCode = $binCode + ($funct3 << 12);
		$binCode = $binCode + ($rs1 << 15);
		$binCode = $binCode + ($imm_0_11 << 20);
		$binCode = pack("V", $binCode);
		return($binCode);
	}
	
	private function S类型($imm_5_11, $rs2, $rs1, $funct3, $imm_0_4, $opCode)
	{
		$binCode = 0b0;
		$binCode = $binCode + $opCode;
		$binCode = $binCode + ($imm_0_4 << 7);
		$binCode = $binCode + ($funct3 << 12);
		$binCode = $binCode + ($rs1 << 15);
		$binCode = $binCode + ($rs2 << 20);
		$binCode = $binCode + ($imm_5_11 << 25);
		$binCode = pack("V", $binCode);
		return($binCode);

	}
	
	private function B类型($imm_12, $imm_5_10, $rs2, $rs1, $funct3, $imm_1_4, $imm_11, $opCode)
	{
		$binCode = 0b0;
		$binCode = $binCode + $opCode;
		$binCode = $binCode + ($imm_11 << 7);
		$binCode = $binCode + ($imm_1_4 << 8);
		$binCode = $binCode + ($funct3 << 12);
		$binCode = $binCode + ($rs1 << 15);
		$binCode = $binCode + ($rs2 << 20);
		$binCode = $binCode + ($imm_5_10 << 25);
		$binCode = $binCode + ($imm_12 << 31);
		$binCode = pack("V", $binCode);
		return($binCode);
	
	}
	
	private function U类型($imm_12_31, $rd, $opCode)
	{
		$binCode = 0b0;
		$binCode = $binCode + $opCode;
		$binCode = $binCode + ($rd << 7);
		$binCode = $binCode + ($imm_12_31 << 12);
		$binCode = pack("V", $binCode);
		return($binCode);

	}
	
	private function J类型($imm_20, $imm_1_10, $imm_11, $imm_12_19, $rd, $opCode)
	{
		$binCode = 0b0;
		$binCode = $binCode + $opCode;
		$binCode = $binCode + ($rd << 7);
		$binCode = $binCode + ($imm_12_19 << 12);
		$binCode = $binCode + ($imm_11 << 20);
		$binCode = $binCode + ($imm_1_10 << 21);
		$binCode = $binCode + ($imm_20 << 31);
		$binCode = pack("V", $binCode);
		return($binCode);

	}

	private function 直接数处理($immIn, $type, $u = 0)
	{
		$m = count($this->全局标签);
		for ($j = 0; $j < $m; $j++)
		{
			if ($this->全局标签[$j]["标签名"] == $immIn)
            {
                $imm = $this->全局标签[$j]["段基址"] + $this->全局标签[$j]["偏移"];
                goto NUMOP;
            }
		}

		$m = count($this->局部标签);
		for ($j = 0; $j < $m; $j++)
		{
			if ($this->局部标签[$j]["标签名"] == $immIn)
            {
                $imm = $this->局部标签[$j]["段基址"] + $this->局部标签[$j]["偏移"];
                goto NUMOP;
            }
		}

		$imm = intval($immIn,0);
		if ($u == 1) $imm = abs($imm);

	NUMOP:
		switch ($type)
		{
			case 'I':
				$n = $imm & 0b00000000000000000000111111111111;
				return($n);
			case 'S':
				$n[0] = $imm & 0b00000000000000000000000000011111;
				$n[1] = $imm & 0b00000000000000000000111111100000;
				$n[1] = $n[1] >> 5;
				return($n);
			case 'B':
				$n[0] = $imm & 0b00000000000000000000000000011110;
				$n[0] = $n[0] >> 1;
				$n[1] = $imm & 0b00000000000000000000011111100000;
				$n[1] = $n[1] >> 5;
				$n[2] = $imm & 0b00000000000000000000100000000000;
				$n[2] = $n[2] >> 11;
				$n[3] = $imm & 0b00000000000000000001000000000000;
				$n[3] = $n[3] >> 12;
				return($n);
			case 'U':
				$n = $imm & 0b11111111111111111111000000000000;
				$n = $n >> 12;
				return($n);
			case 'J':
				$n[0] = $imm & 0b00000000000000000000011111111110;
				$n[0] = $n[0] >> 1;
				$n[1] = $imm & 0b00000000000000000000100000000000;
				$n[1] = $n[1] >> 11;
				$n[2] = $imm & 0b00000000000011111111000000000000;
				$n[2] = $n[2] >> 12;
				$n[3] = $imm & 0b00000000000100000000000000000000;
				$n[3] = $n[3] >> 20;
				return($n);
            case 'CSR':
                $n = $imm & 0b00000000000000000000000000011111;
                return($n);
		}
	}

	private function 寄存器($regName)
	{
		switch ($regName)
		{
			case 'x0':	case 'zero':	$regBin = 0b00000; break;
			case 'x1':	case 'ra':		$regBin = 0b00001; break;
			case 'x2':	case 'sp':		$regBin = 0b00010; break;
			case 'x3':	case 'gp':		$regBin = 0b00011; break;
			case 'x4':	case 'tp':		$regBin = 0b00100; break;
			case 'x5':	case 't0':		$regBin = 0b00101; break;
			case 'x6':	case 't1':		$regBin = 0b00110; break;
			case 'x7':	case 't2':		$regBin = 0b00111; break;
			case 'x8':	case 's0':		$regBin = 0b01000; break;
			case 'x9':	case 's1':		$regBin = 0b01001; break;
			case 'x10':	case 'a0':		$regBin = 0b01010; break;
			case 'x11':	case 'a1':		$regBin = 0b01011; break;
			case 'x12':	case 'a2':		$regBin = 0b01100; break;
			case 'x13':	case 'a3':		$regBin = 0b01101; break;
			case 'x14':	case 'a4':		$regBin = 0b01110; break;
			case 'x15':	case 'a5':		$regBin = 0b01111; break;
			case 'x16':	case 'a6':		$regBin = 0b10000; break;
			case 'x17':	case 'a7':		$regBin = 0b10001; break;
			case 'x18':	case 's2':		$regBin = 0b10010; break;
			case 'x19':	case 's3':		$regBin = 0b10011; break;
			case 'x20':	case 's4':		$regBin = 0b10100; break;
			case 'x21':	case 's5':		$regBin = 0b10101; break;
			case 'x22':	case 's6':		$regBin = 0b10110; break;
			case 'x23':	case 's7':		$regBin = 0b10111; break;
			case 'x24':	case 's8':		$regBin = 0b11000; break;
			case 'x25':	case 's9':		$regBin = 0b11001; break;
			case 'x26':	case 's10':		$regBin = 0b11010; break;
			case 'x27':	case 's11':		$regBin = 0b11011; break;
			case 'x28':	case 't3':		$regBin = 0b11100; break;
			case 'x29':	case 't4':		$regBin = 0b11101; break;
			case 'x30':	case 't5':		$regBin = 0b11110; break;
			case 'x31':	case 't6':		$regBin = 0b11111; break;
            case 'mvendorid':		$regBin = 0xf11;    break;
            case 'marchid':		   	$regBin = 0xf12;    break;
            case 'mimpid':		   	$regBin = 0xf13;    break;
            case 'mhartid':		   	$regBin = 0xf14;    break;
            case 'mstatus':		   	$regBin = 0x300;    break;
            case 'misa':		   	$regBin = 0x301;    break;
            case 'medeleg':		   	$regBin = 0x302;    break;
            case 'mideleg':		   	$regBin = 0x303;    break;
            case 'mie':		       	$regBin = 0x304;    break;
            case 'mtvec':		   	$regBin = 0x305;    break;
            case 'mcounteren':	   	$regBin = 0x306;    break;
            case 'mstatush':	   	$regBin = 0x310;    break;
            case 'mscratch':		$regBin = 0x340;    break;
            case 'mepc':    		$regBin = 0x341;    break;
            case 'mcause':			$regBin = 0x342;    break;
            case 'mtval':			$regBin = 0x343;    break;
            case 'mip':		    	$regBin = 0x344;    break;
            case 'minst':	    	$regBin = 0x34a;    break;
            case 'mtval2':	    	$regBin = 0x34b;    break;
            case 'pmpcfg0':         $regBin = 0x3a0;    break;
            case 'pmpcfg1':         $regBin = 0x3a1;    break;
            case 'pmpcfg2':         $regBin = 0x3a2;    break;
            case 'pmpcfg3':         $regBin = 0x3a3;    break;
            case 'pmpaddr0':        $regBin = 0x3b0;    break;
            case 'pmpaddr1':        $regBin = 0x3b1;    break;
            case 'pmpaddr2':        $regBin = 0x3b2;    break;
            case 'pmpaddr3':        $regBin = 0x3b3;    break;
            case 'pmpaddr4':        $regBin = 0x3b4;    break;
            case 'pmpaddr5':        $regBin = 0x3b5;    break;
            case 'pmpaddr6':        $regBin = 0x3b6;    break;
            case 'pmpaddr7':        $regBin = 0x3b7;    break;
            case 'pmpaddr8':        $regBin = 0x3b8;    break;
            case 'pmpaddr9':        $regBin = 0x3b9;    break;
            case 'pmpaddr10':       $regBin = 0x3ba;    break;
            case 'pmpaddr11':       $regBin = 0x3bb;    break;
            case 'pmpaddr12':       $regBin = 0x3bc;    break;
            case 'pmpaddr13':       $regBin = 0x3bd;    break;
            case 'pmpaddr14':       $regBin = 0x3be;    break;
            case 'pmpaddr15':       $regBin = 0x3bf;    break;
            case 'mcycle':		   	$regBin = 0xb00;    break;
            case 'minstret':	   	$regBin = 0xb02;    break;
            case 'mcycleh':		   	$regBin = 0xb80;    break;
            case 'minstreth':	   	$regBin = 0xb82;    break;
            case 'cycle':		   	$regBin = 0xc00;    break;
            case 'time':		   	$regBin = 0xc01;    break;
            case 'instret':		   	$regBin = 0xc02;    break;
            case 'cycleh':		   	$regBin = 0xc80;    break;
            case 'timeh':		   	$regBin = 0xc81;    break;
            case 'instreth':	   	$regBin = 0xc82;    break;
            default:
                //$regBin = 0x0;
		}
		return $regBin;
	}

}

?>